 package graph_viewer.animator;

import java.awt.*;
import javax.swing.*;

import graph_viewer.animator.*;
import graph_viewer.canvas.*;
import graph_viewer.structure.*;
import graph_viewer.util.*;
/**
 * the super interface of Animator.
 * now no public method defined.
 */

public abstract class Basic_Animator implements  Animator{		
	//template hooker//==============================================================
	abstract protected double find_min_move_distance();
	abstract protected double find_animation_rate();
	//============================================================================		

	//============================================================================
	// protected methods
	//============================================================================		
	protected double	set_up_motion_distance( Point from_position_center, Point to_position_center ){
		double node_distance	= from_position_center.distance( to_position_center );

		double motion_distance	 = node_distance * find_animation_rate();

		double min_move_distance	 = find_min_move_distance();

		if ( motion_distance <  min_move_distance ){
			motion_distance = min_move_distance; 
		}

		return motion_distance;
	}
	
	protected void clear_range( JComponent animation_board, Node_Position np ){
		Rectangle position_range	= np.find_position_range();
		
		Debug.println( "Animator.clear_range()..." + position_range, 3);
		animation_board.paintImmediately( position_range );
	}

	protected void clear_range( JComponent animation_board ){
		Animator_Util.clear_range( animation_board );
	}

	protected void draw_range( JComponent animation_board, Node_Position np ){
		int[]	location = np.find_location();
		int	
			width	= np.get_width(),
			height	= np.get_height();
				
		animation_board.getGraphics().drawRect( location[0], location[1], width, height );
	}
	
	
	protected boolean move_along_line( Point from_point, Point to_point, double motion_distance ){
		if ( from_point.equals(to_point) ){
			return false;
		}
		
		double distance_to_dest	= from_point.distance( to_point );

		//Debug.println( "When move along a line, from:" + from_point + " to: " + to_point + ", the distance_to_dest: " + distance_to_dest, 3 );
		if ( distance_to_dest < motion_distance ){
			from_point.setLocation( to_point );

			return true;
		}
		
		if ( Animator_Util.is_x_align( from_point, to_point ) ){
			move_along_horizontal_line( from_point, to_point, motion_distance );
		}else if ( Animator_Util.is_y_align( from_point, to_point ) ){
			move_along_vertical_line( from_point, to_point, motion_distance );
		}else{
			move_along_slant_line( from_point, to_point, motion_distance );
		}			
				
		return true;
	}

	private void move_along_horizontal_line( Point from_point, Point to_point, double motion_distance ){		
		int move_direction	= 0;
		
		if ( Animator_Util.is_left( from_point, to_point ) ){
			move_direction	= 1;
		}else if ( Animator_Util.is_right( from_point, to_point ) ){
			move_direction	= -1;
		}
		
		int 
			arrived_x	= (int)( from_point.getX() + move_direction * motion_distance ),
			arrived_y	= (int)from_point.getY();

		from_point.move( arrived_x, arrived_y );

	}

	private void move_along_vertical_line( Point from_point, Point to_point, double motion_distance ){		
		int move_direction	= 0;
		
		if ( Animator_Util.is_below( from_point, to_point ) ){
			move_direction	= -1;
		}else if ( Animator_Util.is_above( from_point, to_point ) ){
			move_direction	= 1;
		}
		
		int 
			arrived_x	= (int)from_point.getX(),
			arrived_y	= (int)( from_point.getY() + move_direction * motion_distance );
		
		from_point.move( arrived_x, arrived_y );
	}

	private void move_along_slant_line( Point from_point, Point to_point, double motion_distance ){				
		double 
			tangent		= Layout_Util.find_line_tangent( from_point, to_point ),
			x_motion		= Math.sqrt( motion_distance * motion_distance/ ( 1 + tangent * tangent ) ),
			y_motion	= x_motion * tangent;

		int
			x_move_direction	= 0,
			y_move_direction = 0;

		if ( Animator_Util.is_left( from_point, to_point ) ){
			x_move_direction	= 1;
		}else if ( Animator_Util.is_right( from_point, to_point ) ){
			x_move_direction	= -1;
		}

		if ( Animator_Util.is_below( from_point, to_point ) ){
			y_move_direction	= -1;
		}else if ( Animator_Util.is_above( from_point, to_point ) ){
			y_move_direction	= 1;
		}

		int
			arrived_x	= (int)( from_point.getX() + x_move_direction * x_motion ),
			arrived_y	= (int)( from_point.getY() + y_move_direction * y_motion );
		
		from_point.move( arrived_x, arrived_y );
	}

}//:~